#include "Mesh.h"

Mesh::Mesh(void)
{
	sBondIterator = 0;
}
Mesh::Mesh(vector<Point> pList, double minElemSize)
{
	sBondIterator = 0;
	this->triangulateShape(pList,minElemSize);
}
Mesh::~Mesh(void)
{
}
void Mesh::triangulateShape(vector<Point> pList, double minElemSize)
{
	constrPointList.clear();
	vertexList.clear();
	elementList.clear();
	fBoundaryList.clear();
	sBoundaryList.clear();

	constrPointList = pList;

	int xSize;
	int ySize;

	int xSpread;
	int ySpread;

	int xMin = constrPointList[0].x;
	int xMax = constrPointList[0].x;
	int yMin = constrPointList[0].y;
	int yMax = constrPointList[0].y;

	bool xMod = false;
	bool yMod = false;

	int xModVal = 0;
	int yModVal = 0;

	// find minimum and maximum dim for calculating size
	for (unsigned int i = 0; i < constrPointList.size(); ++i)
	{
		if (constrPointList[i].x < xMin)	{xMin = constrPointList[i].x;}
		if (constrPointList[i].x > xMax)	{xMax = constrPointList[i].x;}
		if (constrPointList[i].y < yMin)	{yMin = constrPointList[i].y;}
		if (constrPointList[i].y > yMax)	{yMax = constrPointList[i].y;}
	}

	xLeft = xMin;
	xRight = xMax;
	yUp = yMin;
	yDown = yMax;

	// calculating size
	xSize = xMax - xMin;
	ySize = yMax - yMin;

	xSpread = xSize;
	ySpread = ySize;

	// detecting leftovers for X dim
	if (fmod(xSize, minElemSize))
	{
		xModVal = (int)fmod(xSize, minElemSize);
		xMod = true;
	}

	// detecting leftovers for Y dim
	if (fmod(ySize, minElemSize))
	{
		yModVal = (int)fmod(ySize, minElemSize);
		yMod = true;
	}

	// creating points for mesh (seeding)
	int globVertexIndex = 0;
	int xOff = xMin;
	int yOff = yMin;
	bool isRunning = true;

	xSize = xMax;
	ySize = yMax;

	while(isRunning)
	{
		// stopping condition
		if ((yOff == ySize)&&(xOff == xSize))
		{
			isRunning = false;
		}

		// adding point to
		vertexList.push_back(mPoint(xOff,yOff,globVertexIndex));

		// switch to next vertical line of points (new X ccords)
		if (yOff == ySize)
		{
			if ((xMod)&&(xSize - xModVal == xOff))	{xOff += xModVal;}
			else									{xOff += (int)minElemSize;}
			yOff = yMin;
			globVertexIndex++;
			continue;
		}

		// new Y coordinates for point
		if ((yMod)&&(ySize - yModVal == yOff))	{yOff += yModVal;}
		else									{yOff += (int)minElemSize;}

		// next global index for point
		globVertexIndex++;
	}

	/*
	while(isRunning)
	{
		// stopping condition
		if ((yOff == ySize)&&(xOff == xSize))
		{
			isRunning = false;
		}

		// adding point to
		vertexList.push_back(mPoint(xOff,yOff,globVertexIndex));

		// switch to next vertical line of points (new X ccords)
		if (yOff == ySize)
		{
			if ((xMod)&&(xSize - xModVal == xOff))	{xOff += xModVal;}
			else									{xOff += (int)minElemSize;}
			yOff = yMin;
			globVertexIndex++;
			continue;
		}

		// new Y coordinates for point
		if ((yMod)&&(ySize - yModVal == yOff))	{yOff += yModVal;}
		else									{yOff += (int)minElemSize;}

		// next global index for point
		globVertexIndex++;
	}
	*/

	// calculating how many points in row / column
	int xDimPointNum = int(xSpread / minElemSize) + 1;
	int yDimPointNum = int(ySpread / minElemSize) + 1;

	if (xMod)	{xDimPointNum++;}
	if (yMod)	{yDimPointNum++;}

	// constructing actual mesh
	int globElemIndex = 0;
	int aInd;
	int bInd;
	int cInd;
	int dInd;

	for (int i = 0; i < xDimPointNum - 1; ++i)
	{
		for (int j = 0; j < yDimPointNum - 1; ++j)
		{
			// calculate indexes for points building new elements
			aInd = i * yDimPointNum + j;
			bInd = aInd + 1;
			cInd = aInd + yDimPointNum;
			dInd = cInd + 1;

			// add new elements to the vector
			elementList.push_back(Element(&vertexList[aInd],&vertexList[bInd],&vertexList[dInd],globElemIndex++));
			elementList.push_back(Element(&vertexList[aInd],&vertexList[dInd],&vertexList[cInd],globElemIndex++));
		}
	}
}
void Mesh::addFirstBoundary( FirstBoundary val )
{
	fBoundaryList.push_back(val);
}
void Mesh::addSecondBoundary( SecondBoundary val )
{
	val.UniqueIndex(sBondIterator);
	sBoundaryList.push_back(val);
	sBondIterator++;
}
void Mesh::setKFactor( int val )
{
	this->kFactor = val;
}
void Mesh::setScale( double val )
{
	this->scale = val;
}